/*
 * Rule.h
 *
 * Una Regla es utilizada por el Parser para saber si lo que esta parseando
 * tiene un formato valido. De esta manera, se puede usar el mismo Parser,
 * para validar archivos con distintos formatos, simplemente inyectando una
 * Regla distinta.
 *
 * En este archivo se definen las clases:
 *     - Rule      : Clase abstracta representa una regla generica.
 *     - NodesRule : Subclase de Rule. Utilizada para el archivo Vertices.txt.
 *     - RoadsRule : Subclase de Rule. Utilizada para el archivo Aristas.txt.
 *     - MapLocationRule : Subclase de Rule. Utiliazada para el archivo
 *     		ObjetosDeMapa.txt.
 *     - ConfigEntryRule : Subclase de Rule. Utilizada para el archivo
 *     		Configuracion.txt.
 *
 * Las implementaciones estan en el archivo Rule.cpp
 *
 * @author marcos
 */

#ifndef RULE_H_
#define RULE_H_

#include "ParsedData.h"
#include "exceptions/InvalidDataException.h"
#include <string>

namespace parser {

/* @class Rule
 * Representa una regla de parseo. El parser depende de una Regla para poder
 * parsear los valores que lee.
 *
 * La regla contiene el delimitador que separa los datos dentro de un registro.
 * Ademas devuelve un objeto ParsedData que contiene los valores leidos.
 * Utiliza excepciones en caso de recibir valores insuficientes o incorrectos y
 * guarda warnings (dentro de ParsedData).
 */
class Rule {
public:
	/*
	 * Construye una nueva regla
	 */
	Rule(char dataSeparator);
	virtual ~Rule();
	/* Agrega un valor para chequear contra esta regla.
	 *
	 * Si hay un valor de mas, agrega un "warning" al objeto resultado.
	 * @throws InvalidValue si el valor es invalido segun esta regla.
	 */
	virtual Rule* addValue(std::string value) throw (InvalidDataException) = 0;

	/* Devuelve los valores recibidos ya validados, dentro de un objeto ParsedData.
	 * Recibe un parametro clearData que indica si se tiene que limpiar los datos
	 * luego de ser entregados.
	 *
	 * @throws NotEnoughValues si faltan valores de acuerdo a esta regla.
	 */
	virtual ParsedData* getParsedData(bool clearData)
			throw (InvalidDataException);
	/*
	 * Descarta el ParsedData con el que se estaba trabajando y comienza con uno nuevo
	 *
	 */
	virtual void discardCurrentParsedData();
	/*
	 * Devuelve el separador de datos
	 */
	char getDataSeparator();

protected:
	short int k; // cantidad de valores recibidos
	short int n; // total de valores a recibir
	char separator; // caracter separador de datos
	/*
	 * Permite a las sub clases construir un nuevo parsedData
	 */
	virtual ParsedData* buildNewParsedData() {
		return NULL;
	}
	/*
	 * Resetea la informacion de ParsedData
	 */
	void resetParsedData();
	virtual bool isImportantField(int k) = 0;
	ParsedData* parsedData; // almacena los datos parseados y los warnings
};

/* @class IntersectionRule
 * Representa una regla para el archivo de vertices (Vertices.txt).
 * @see Rule
 */
class IntersectionRule: public Rule {
public:
	/* constructor
	 * @param dataSeparator el separador de datos de un registro */
	IntersectionRule(char dataSeparator);
	/* destructor por defecto */
	virtual ~IntersectionRule();
	IntersectionRule* addValue(std::string value) throw (InvalidDataException);
protected:
	virtual ParsedData* buildNewParsedData();
	virtual bool isImportantField(int k);
};

/* @class RoadRule
 * Representa una regla para el archivo de aristas (Aristas.txt).
 * @see Rule
 */
class RoadRule: public Rule {
public:
	/* constructor
	 * @param dataSeparator el separador de datos de un registro */
	RoadRule(char dataSeparator);
	/* destructor por defecto */
	virtual ~RoadRule();
	RoadRule* addValue(std::string value) throw (InvalidDataException);
protected:
	virtual ParsedData* buildNewParsedData();
	virtual bool isImportantField(int k);
};

/*
 * Clase que representa una regla de parseo para el archivo de objetos de mapa (ObjetosDeMapa.txt).
 */
class MapLocationRule: public Rule {
public:
	/*
	 * Constructor. Recibe el caracter que va a ser usado para separar datos en el archivo.
	 */
	MapLocationRule(char dataSeparator);

	/*
	 * Destructor por defecto.
	 */
	virtual ~MapLocationRule();

	/*
	 * Metodo para agregar un valor leido de archivo.
	 */
	virtual MapLocationRule* addValue(std::string value)
			throw (InvalidDataException);

protected:
	virtual ParsedData* buildNewParsedData();

	virtual bool isImportantField(int k);
};

/*
 * Clase que representa una regla para parsear el archivo de configuracion de la
 * aplicacion.
 */
class ConfigEntryRule: public Rule {
public:
	/*
	 * Constructor. Recibe como parametro el separador de linea.
	 */
	ConfigEntryRule(char dataSeparator);

	/*
	 * Destructor.
	 */
	virtual ~ConfigEntryRule();

	/*
	 * Metodo para agregar un valor al objeto.
	 */
	virtual ConfigEntryRule* addValue(std::string value)
			throw (InvalidDataException);

protected:
	virtual ParsedData* buildNewParsedData();

	virtual bool isImportantField(int k);
};

} // end of namespace

#endif /* RULE_H_ */
